<template>
  <div class="h-[600px] p-2.5">
    <p class="flex justify-center mb-4 text-2xl font-bold">串口通信</p>

    <div class="flex-1 my-2 h-2/3">
      <el-row class="h-full" :gutter="20">
        <el-col :span="6">
          <div class="flex flex-col gap-5 p-2.5 border h-full rounded-md">
            <div>串口设置</div>
            <!-- 端口 -->
            <div class="relative flex items-center gap-2">
              <div class="min-w-12">端 口</div>
              <el-input
                @focus="showPort = true"
                @blur="close"
                v-model="path"
                type="text"
                placeholder="输入端口路径"
              ></el-input>
              <div v-if="showPort" class="absolute top-[36px] z-50 right-0 p-2 bg-white left-14 border rounded">
                <div v-for="(item, index) in portList" :key="index" @click="handleClickItem(item)">{{ item.path }}</div>
              </div>
            </div>
            <!-- 波特率 -->
            <div class="flex items-center gap-2">
              <div class="min-w-12">波特率</div>
              <el-select v-model="baudRate" placeholder="选择端口波特率">
                <el-option v-for="item in baudRateList" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </div>
            <!-- 数据位 -->
            <div class="flex items-center gap-2">
              <div class="min-w-12">数据位</div>
              <el-select v-model="dataBit" placeholder="选择端口数据位">
                <el-option v-for="item in dataBitList" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </div>
            <!-- 校验位 -->
            <div class="flex items-center gap-2">
              <div class="min-w-12">校验位</div>
              <el-select v-model="parityBit" placeholder="选择端口校验位">
                <el-option v-for="item in parityBitList" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </div>
            <!-- 停止位 -->
            <div class="flex items-center gap-2">
              <div class="min-w-12">停止位</div>
              <el-select v-model="stopBit" placeholder="选择端口停止位">
                <el-option v-for="item in stopBitList" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </div>
            <div class="flex justify-end">
              <el-button type="primary" @click="sacnPort">扫描串口</el-button>
              <el-button v-if="!isOpen" type="primary" @click="handleOpen">打开</el-button>
              <el-button v-else type="danger" @click="handleClose">关闭</el-button>
            </div>
          </div>
        </el-col>
        <el-col :span="10">
          <div class="flex flex-col h-full">
            <div class="flex-1 p-2 border rounded-md">{{ sendMsg2 }}</div>
            <div class="flex items-center gap-2 mt-2">
              <el-input v-model="sendMsg" class="h-full" type="textarea" placeholder="发送数据" />
              <el-button type="primary" @click="handleSendMsg">发送</el-button>
            </div>
          </div>
        </el-col>
        <el-col :span="8">
          <div class="h-full p-2 border rounded-md">{{ receiveMsg }}</div>
        </el-col>
      </el-row>
    </div>
  </div>
</template>

<script setup lang="ts">
  import { SerialPort, SerialPortMock, ReadlineParser } from 'serialport'

  const sendMsg = ref('')
  const sendMsg2 = ref('')
  const receiveMsg = ref('')
  const port = ref<SerialPort>()
  const portList = ref<any[]>([])
  const path = ref('')
  const baudRate = ref(9600)
  const baudRateList = [
    {
      label: '9600',
      value: 9600
    },
    {
      label: '19200',
      value: 19200
    },
    {
      label: '38400',
      value: 38400
    },
    {
      label: '57600',
      value: 57600
    },
    {
      label: '115200',
      value: 115200
    }
  ]

  const dataBit = ref(8)
  const dataBitList = [
    {
      label: '5',
      value: 5
    },
    {
      label: '6',
      value: 6
    },
    {
      label: '7',
      value: 7
    },
    {
      label: '8',
      value: 8
    }
  ]

  const stopBit = ref(1)
  const stopBitList = [
    {
      label: '1',
      value: 1
    },
    {
      label: '1.5',
      value: 1.5
    },
    {
      label: '2',
      value: 2
    }
  ]

  const parityBit = ref('None')
  const parityBitList = [
    {
      label: 'None',
      value: 'None'
    },
    {
      label: 'Even',
      value: 'Even'
    },
    {
      label: 'Odd',
      value: 'Odd'
    },
    {
      label: 'Mark',
      value: 'Mark'
    },
    {
      label: 'Space',
      value: 'Space'
    }
  ]

  const showPort = ref(false)
  const isOpen = ref(false)

  const sacnPort = async () => {
    let res = await SerialPort.list()
    if (res.length) {
      path.value = res[0].path
    }
    let mock = await SerialPortMock.list()
    console.log(res, '扫描到的串口')
    portList.value = res.concat(mock)
  }

  const handleSendMsg = () => {
    unref(port)?.write(unref(sendMsg), (err) => {
      if (err) {
        console.log('写入串口数据失败', err)
        return ElMessage.error(`写入${path}串口数据失败`)
      }
      sendMsg2.value = unref(sendMsg)
      sendMsg.value = ''
    })
  }

  const handleOpen = () => {
    port.value = new SerialPort(
      {
        path: unref(path),
        baudRate: unref(baudRate)
      },
      (err: any) => {
        if (err) {
          console.log(err, '打开串口失败')
          ElMessage.error(`打开${unref(path)}串口失败！`)
          return
        }

        const parser = new ReadlineParser()
        unref(port)?.pipe(parser)

        parser.on('data', (data: any) => {
          console.log('收到的数据:', data.toString())
          // receiveMsg.value += '\n' + data.toString() + '\n'
        })

        unref(port)?.on('close', (err: any) => {
          if (err) {
            console.log(err, '串口关闭失败')
            return ElMessage.error(`串口${unref(path)}关闭失败！`)
          }
          console.log('串口已关闭')
          isOpen.value = false
        })

        unref(port)?.on('error', (err) => {
          if (err) {
            console.log(err, 'error')
          }
        })
      }
    )
  }

  const handleClose = () => {
    if (!unref(port)) return ElMessage.warning('串口未打开！')
    unref(port)!.close()
  }

  const handleClickItem = (item: any) => {
    path.value = item.path
  }

  watch(
    () => port,
    () => {
      if (unref(port)) {
        isOpen.value = unref(port)!.isOpen
      }
    },
    {
      immediate: true,
      deep: true
    }
  )

  onMounted(() => {
    sacnPort()
  })

  const close = () => {
    setTimeout(() => {
      showPort.value = false
    }, 300)
  }

  // const createMockPort = (num: number = 2) => {
  //   for (let i = 1; i <= num; i++) {
  //     SerialPortMock.binding.createPort(`MockCOM${i}`, { echo: true, record: true })
  //   }
  // }

  // createMockPort(2)

  window.addEventListener('beforeunload', () => {
    unref(port)?.close()
  })
</script>

<style scoped lang="less">
  body {
    height: 100%;
  }

  :deep(.el-textarea__inner) {
    height: 100%;
    resize: none;
  }
</style>
